浅析Android10动态授权流程 您所在的位置:网站首页 require permissionflag 浅析Android10动态授权流程

浅析Android10动态授权流程

#浅析Android10动态授权流程| 来源: 网络整理| 查看: 265

做app开发经常需要申请动态权限,比如WRITE_EXTERNAL_STORAGE、ACCESS_FINE_LOCATION,那么今天就从源码分析,动态权限到底是怎么个流程,Android系统是怎么维护各个app的权限状态的,基于Android 10。对源码敏感的同学可以直接拉到底部看总结

检查权限

首先权限申请入口位于frameworks/base/core/java/android/content/Context.java

public abstract class Context { //省略部分代码 /** * Determine whether you have been granted a particular permission. * * @param permission The name of the permission being checked. * * @return {@link PackageManager#PERMISSION_GRANTED} if you have the * permission, or {@link PackageManager#PERMISSION_DENIED} if not. * * @see PackageManager#checkPermission(String, String) * @see #checkCallingPermission(String) */ @PackageManager.PermissionResult public abstract int checkSelfPermission(@NonNull String permission); //省略部分代码 }

checkSelfPermission()是一个抽象方法,方法实现在Context的子类frameworks/base/core/java/android/app/ContextImpl.java当中

/** * Common implementation of Context API, which provides the base * context object for Activity and other application components. */ class ContextImpl extends Context { //省略部分代码 @Override public int checkSelfPermission(String permission) { if (permission == null) { throw new IllegalArgumentException("permission is null"); } return checkPermission(permission, Process.myPid(), Process.myUid()); } @Override public int checkPermission(String permission, int pid, int uid) { if (permission == null) { throw new IllegalArgumentException("permission is null"); } //获取ActivityManagerService代理对象 final IActivityManager am = ActivityManager.getService(); if (am == null) { // Well this is super awkward; we somehow don't have an active // ActivityManager instance. If we're testing a root or system // UID, then they totally have whatever permission this is. final int appId = UserHandle.getAppId(uid); //如果是root用户或者是系统应用,直接返回已授权状态 if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) { Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " holds " + permission); return PackageManager.PERMISSION_GRANTED; } Slog.w(TAG, "Missing ActivityManager; assuming " + uid + " does not hold " + permission); return PackageManager.PERMISSION_DENIED; } try { //通过ActivityManagerService来检查权限 return am.checkPermission(permission, pid, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } //省略部分代码 }

ContextImpl通过frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java来检查权限

public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { //省略部分代码 @Override public int checkPermission(String permission, int pid, int uid) { if (permission == null) { return PackageManager.PERMISSION_DENIED; } //注意,参数4传的-1,参数5传的true return checkComponentPermission(permission, pid, uid, -1, true); } public static int checkComponentPermission(String permission, int pid, int uid, int owningUid, boolean exported) { //如果是AMS进程调用此方法,则直接返回已授权状态 if (pid == MY_PID) { return PackageManager.PERMISSION_GRANTED; } return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported); } /** @hide */ @UnsupportedAppUsage public static int checkComponentPermission(String permission, int uid, int owningUid, boolean exported) { // Root, system server get to do everything. final int appId = UserHandle.getAppId(uid); //如果是root用户或者是系统应用,直接返回已授权状态 if (appId == Process.ROOT_UID || appId == Process.SYSTEM_UID) { return PackageManager.PERMISSION_GRANTED; } // Isolated processes don't get any permissions. //孤立的进程不具有任何权限 if (UserHandle.isIsolated(uid)) { return PackageManager.PERMISSION_DENIED; } // If there is a uid that owns whatever is being accessed, it has // blanket access to it regardless of the permissions it requires. //owningUid为刚刚我们传的参数4,为-1,所以显然这里不满足 if (owningUid >= 0 && UserHandle.isSameApp(uid, owningUid)) { return PackageManager.PERMISSION_GRANTED; } // If the target is not exported, then nobody else can get to it. //exported为刚刚我们传的参数5,为true,所以显然这里不满足,这里的意思是如果目标进程不对外开放,则任何对象都无法访问 if (!exported) { /* RuntimeException here = new RuntimeException("here"); here.fillInStackTrace(); Slog.w(TAG, "Permission denied: checkComponentPermission() owningUid=" + owningUid, here); */ return PackageManager.PERMISSION_DENIED; } if (permission == null) { return PackageManager.PERMISSION_GRANTED; } try { //通过PackageManagerService检查权限 return AppGlobals.getPackageManager() .checkUidPermission(permission, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } //省略部分代码 }

先是处理了一些特殊情况的逻辑,最终权限判断交由frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java来完成

public class PackageManagerService extends IPackageManager.Stub implements PackageSender { //省略部分代码 @Override public int checkUidPermission(String permName, int uid) { final CheckPermissionDelegate checkPermissionDelegate; synchronized (mPackages) { if (mCheckPermissionDelegate == null) { return checkUidPermissionImpl(permName, uid); } checkPermissionDelegate = mCheckPermissionDelegate; } //最终都执行checkUidPermissionImpl() return checkPermissionDelegate.checkUidPermission(permName, uid, PackageManagerService.this::checkUidPermissionImpl); } private int checkUidPermissionImpl(String permName, int uid) { synchronized (mPackages) { //先获取packageName final String[] packageNames = getPackagesForUid(uid); PackageParser.Package pkg = null; final int N = packageNames == null ? 0 : packageNames.length; for (int i = 0; pkg == null && i < N; i++) { pkg = mPackages.get(packageNames[i]); } //执行PermissionManagerServiceInternal的checkUidPermission() return mPermissionManager.checkUidPermission(permName, pkg, uid, getCallingUid()); } } //省略部分代码 }

可以看到,最终会执行PermissionManagerServiceInternal的checkUidPermission(),checkUidPermission()是一个抽象方法,由PermissionManagerServiceInternal的子类PermissionManagerService.PermissionManagerServiceInternalImpl来实现

/** * Manages all permissions and handles permissions related tasks. */ public class PermissionManagerService { //省略部分代码 /** * Built-in permissions. Read from system configuration files. Mapping is from * UID to permission name. */ private final SparseArray mSystemPermissions; private class PermissionManagerServiceInternalImpl extends PermissionManagerServiceInternal { //省略部分代码 @Override public int checkUidPermission(String permName, PackageParser.Package pkg, int uid, int callingUid) { //执行PermissionManagerService的checkUidPermission()方法 return PermissionManagerService.this.checkUidPermission(permName, pkg, uid, callingUid); } //省略部分代码 } private int checkUidPermission(String permName, PackageParser.Package pkg, int uid, int callingUid) { //获取调用此Service的进程uid,也就是调用者的uid final int callingUserId = UserHandle.getUserId(callingUid); //callingUserId是否为即时应用,我称之为快应用,免安装的那种 final boolean isCallerInstantApp = mPackageManagerInt.getInstantAppPackageName(callingUid) != null; //uid是否为即时应用,我称之为快应用,免安装的那种 final boolean isUidInstantApp = mPackageManagerInt.getInstantAppPackageName(uid) != null; //获取申请权限的进程id,如果是微信申请权限,则uid指微信,通过日志打印得知,userId与callingUserId相等 final int userId = UserHandle.getUserId(uid); if (!mUserManagerInt.exists(userId)) { return PackageManager.PERMISSION_DENIED; } if (pkg != null) { //非常规场景的处理 if (pkg.mSharedUserId != null) { if (isCallerInstantApp) { return PackageManager.PERMISSION_DENIED; } } else if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) { return PackageManager.PERMISSION_DENIED; } //获取该应用的授权状态,授权状态封装在PermissionState对象当中 final PermissionsState permissionsState = ((PackageSetting) pkg.mExtras).getPermissionsState(); //如果已经授权,则返回PERMISSION_GRANTED if (permissionsState.hasPermission(permName, userId)) { if (isUidInstantApp) { if (mSettings.isPermissionInstant(permName)) { return PackageManager.PERMISSION_GRANTED; } } else { return PackageManager.PERMISSION_GRANTED; } } //如果同权限组中有其他的权限已经授权了,则该组其它权限也直接授权,比如ACCESS_FINE_LOCATION授权了,ACCESS_COURSE_LOCATION也会自动授权 if (isImpliedPermissionGranted(permissionsState, permName, userId)) { return PackageManager.PERMISSION_GRANTED; } } else { //如果pkg为空,说明PMS没有扫描到此安装包,此逻辑应用app不用考虑,通过日志,也没有走到此处 ArraySet perms = mSystemPermissions.get(uid); if (perms != null) { if (perms.contains(permName)) { return PackageManager.PERMISSION_GRANTED; } if (FULLER_PERMISSION_MAP.containsKey(permName) && perms.contains(FULLER_PERMISSION_MAP.get(permName))) { return PackageManager.PERMISSION_GRANTED; } } } //都不满足则返回PERMISSION_DENIED return PackageManager.PERMISSION_DENIED; } //省略部分代码 }

先从PackageParser.Package中读取mExtral字段,此字段为PackageSetting对象,再通过PackageSetting读取当前应用授权状态PermissionState。PackageParser.Package表示从磁盘读取的APK文件的完整信息(PMS在初始化时会扫描磁盘,这里不做具体分析),我们知道一个APK文件包含很多信息,包名,版本号,所有注册的组件,需要申请的权限等等,具体可参考manifest文件和gradle文件,而我们的权限信息就在mExtral字段当中,而mExtral是一个PackageSetting对象,涉及到安装包配置变更的数据都保存在此对象中,其中我们通过getPermissionsState()拿到授权状态PermissionsState,然后通过hasPermission()判断当前申请的权限是否已经授权

public final class PermissionsState { //省略部分代码 @GuardedBy("mLock") private ArrayMap mPermissions; /** * Gets whether the state has a given permission for the specified * user, regardless if this is an install or a runtime permission. * * @param name The permission name. * @param userId The device user id. * @return Whether the user has the permission. */ public boolean hasPermission(String name, int userId) { enforceValidUserId(userId); synchronized (mLock) { if (mPermissions == null) { return false; } PermissionData permissionData = mPermissions.get(name); return permissionData != null && permissionData.isGranted(userId); } } //省略部分代码 }

因为一个ap可能涉及到多个权限申请,所以PermissionsState里定义了一个ArrayMap来保存所有权限的授权状态,map的key为权限名称,value为PermissionData,PermissionData里面定义了一个SparseArray,保存所有用户对当前app指定权限的授权情况

private static final class PermissionData { private final BasePermission mPerm; private SparseArray mUserStates = new SparseArray(); public PermissionData(BasePermission perm) { mPerm = perm; } public PermissionData(PermissionData other) { this(other.mPerm); final int otherStateCount = other.mUserStates.size(); for (int i = 0; i < otherStateCount; i++) { final int otherUserId = other.mUserStates.keyAt(i); PermissionState otherState = other.mUserStates.valueAt(i); mUserStates.put(otherUserId, new PermissionState(otherState)); } } //这里考虑了多用户的情况 public boolean isGranted(int userId) { if (isInstallPermission()) { userId = UserHandle.USER_ALL; } PermissionState userState = mUserStates.get(userId); if (userState == null) { return false; } return userState.mGranted; } //如果用户点击了允许授权,则调用此方法设置 public boolean grant(int userId) { if (!isCompatibleUserId(userId)) { return false; } if (isGranted(userId)) { return false; } PermissionState userState = mUserStates.get(userId); if (userState == null) { userState = new PermissionState(mPerm.getName()); mUserStates.put(userId, userState); } userState.mGranted = true; return true; } //省略部分代码 }

PermissionsState.PermissionState则是定义了权限的名称和权限的授权情况

public final class PermissionsState { //省略部分代码 public static final class PermissionState { //权限名称 private final String mName; //是否授权 private boolean mGranted; private int mFlags; public PermissionState(String name) { mName = name; } public PermissionState(PermissionState other) { mName = other.mName; mGranted = other.mGranted; mFlags = other.mFlags; } public boolean isDefault() { return !mGranted && mFlags == 0; } public String getName() { return mName; } public boolean isGranted() { return mGranted; } public int getFlags() { return mFlags; } } }

以上是Context.checkPermission()的流程

申请权限

下面再来看看Activity.requestPermissions()的流程,fragment的权限申请也是走的宿主Activity的权限申请流程

public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback, WindowControllerCallback, AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient { //省略部分代码 public final void requestPermissions(@NonNull String[] permissions, int requestCode) { if (requestCode < 0) { throw new IllegalArgumentException("requestCode should be >= 0"); } if (mHasCurrentPermissionsRequest) { Log.w(TAG, "Can request only one set of permissions at a time"); // Dispatch the callback with empty arrays which means a cancellation. onRequestPermissionsResult(requestCode, new String[0], new int[0]); return; } //构建Intent Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions); //启动Activity startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null); mHasCurrentPermissionsRequest = true; } //省略部分代码 }

通过PackageManager构建了一个Intent,然后启动了一个Activity

public abstract class PackageManager { //省略部分代码 @SystemApi public static final String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS"; public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) { if (ArrayUtils.isEmpty(permissions)) { throw new IllegalArgumentException("permission cannot be null or empty"); } //隐式Intent,注册了ACTION_REQUEST_PERMISSIONS的Activity可以处理此Intent Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS); intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions); intent.setPackage(getPermissionControllerPackageName()); return intent; } //省略部分代码 }

PackageManager启动了一个隐式的Intent,ACTION为android.content.pm.action.REQUEST_PERMISSIONS,那么注册了该ACTION的即可处理此Intent,而GrantPermissionsActivity就注册了此ACTION

可以看到此Activity的theme设置为了GrantPermissions,而此theme的定义为

true @android:color/transparent true

风格为对话框,没有窗口标题,透明背景,沉浸式状态栏,不就是我们弹出的授权对话框吗

图1

动态授权.png

再看看Activity的处理

public class GrantPermissionsActivity extends Activity implements GrantPermissionsViewHandler.ResultListener { //省略部分代码 private GrantPermissionsViewHandler mViewHandler; private String[] mRequestedPermissions; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); //省略部分代码 //获取要申请的权限 mRequestedPermissions = getIntent().getStringArrayExtra( PackageManager.EXTRA_REQUEST_PERMISSIONS_NAMES); // Don't allow legacy apps to request runtime permissions. //6.0以下不需要动态授权 if (callingPackageInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { // Returning empty arrays means a cancellation. mRequestedPermissions = new String[0]; setResultAndFinish(); return; } //省略部分代码 //根据不同的设备创建不同的Handler if (DeviceUtils.isTelevision(this)) { mViewHandler = new com.android.packageinstaller.permission.ui.television .GrantPermissionsViewHandlerImpl(this, mCallingPackage).setResultListener(this); } else if (DeviceUtils.isWear(this)) { mViewHandler = new GrantPermissionsWatchViewHandler(this).setResultListener(this); } else if (DeviceUtils.isAuto(this)) { mViewHandler = new GrantPermissionsAutoViewHandler(this, mCallingPackage, userHandle) .setResultListener(this); } else { mViewHandler = new com.android.packageinstaller.permission.ui.handheld .GrantPermissionsViewHandlerImpl(this, mCallingPackage, userHandle) .setResultListener(this); } //省略部分代码 //设置页面布局 setContentView(mViewHandler.createView()); //省略部分代码 }

页面布局文件的创建在对应的Handler的createView()方法当中,因为我是在手机上测试的,所以创建的是GrantPermissionsViewHandlerImpl

public class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler, OnClickListener { //省略部分代码 @Override public View createView() { mRootView = (ViewGroup) LayoutInflater.from(mActivity) .inflate(R.layout.grant_permissions, null); int h = mActivity.getResources().getDisplayMetrics().heightPixels; mRootView.setMinimumHeight(h); //省略部分代码 return mRootView; } //省略部分代码 }

打开grant_permissions.xml文件,就是图1中的布局,直接看点击允许和拒绝之后的处理

public class GrantPermissionsViewHandlerImpl implements GrantPermissionsViewHandler, OnClickListener { //省略部分代码 @Override public void onClick(View view) { switch (view.getId()) { case R.id.permission_allow_button: //点击允许 if (mResultListener != null) { view.performAccessibilityAction( AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS); } break; case R.id.permission_allow_always_button: //点击始终允许 if (mResultListener != null) { view.performAccessibilityAction( AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); mResultListener.onPermissionGrantResult(mGroupName, GRANTED_ALWAYS); } break; case R.id.permission_allow_foreground_only_button: //点击运行期间允许 if (mResultListener != null) { view.performAccessibilityAction( AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); mResultListener.onPermissionGrantResult(mGroupName, GRANTED_FOREGROUND_ONLY); } break; case R.id.permission_deny_button: //点击拒绝 if (mResultListener != null) { view.performAccessibilityAction( AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); mResultListener.onPermissionGrantResult(mGroupName, DENIED); } break; case R.id.permission_deny_and_dont_ask_again_button: //点击拒绝且不再提示 if (mResultListener != null) { view.performAccessibilityAction( AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null); mResultListener.onPermissionGrantResult(mGroupName, DENIED_DO_NOT_ASK_AGAIN); } break; //省略部分代码 } } //省略部分代码 }

无论点击什么按钮,都通过ResultListener进行回调,并携带用户选择的结果,GrantPermissionsActivity实现了这个接口,看一下它的处理

public class GrantPermissionsActivity extends Activity implements GrantPermissionsViewHandler.ResultListener { //省略部分代码 @Override public void onPermissionGrantResult(String name, @GrantPermissionsViewHandler.Result int result) { //记录日志 logGrantPermissionActivityButtons(name, result); GroupState foregroundGroupState = getForegroundGroupState(name); GroupState backgroundGroupState = getBackgroundGroupState(name); //如果设备处于锁屏状态,先解除锁屏 if (result == GRANTED_ALWAYS || result == GRANTED_FOREGROUND_ONLY || result == DENIED_DO_NOT_ASK_AGAIN) { KeyguardManager kgm = getSystemService(KeyguardManager.class); if (kgm.isDeviceLocked()) { kgm.requestDismissKeyguard(this, new KeyguardManager.KeyguardDismissCallback() { @Override public void onDismissError() { Log.e(LOG_TAG, "Cannot dismiss keyguard perm=" + name + " result=" + result); } @Override public void onDismissCancelled() { // do nothing (i.e. stay at the current permission group) } @Override public void onDismissSucceeded() { // Now the keyguard is dismissed, hence the device is not locked // anymore //解锁后继续执行此方法 onPermissionGrantResult(name, result); } }); return; } } //根据用户选择执行对应的动作 switch (result) { case GRANTED_ALWAYS : if (foregroundGroupState != null) { onPermissionGrantResultSingleState(foregroundGroupState, true, false); } if (backgroundGroupState != null) { onPermissionGrantResultSingleState(backgroundGroupState, true, false); } break; case GRANTED_FOREGROUND_ONLY : if (foregroundGroupState != null) { onPermissionGrantResultSingleState(foregroundGroupState, true, false); } if (backgroundGroupState != null) { onPermissionGrantResultSingleState(backgroundGroupState, false, false); } break; case DENIED : if (foregroundGroupState != null) { onPermissionGrantResultSingleState(foregroundGroupState, false, false); } if (backgroundGroupState != null) { onPermissionGrantResultSingleState(backgroundGroupState, false, false); } break; case DENIED_DO_NOT_ASK_AGAIN : if (foregroundGroupState != null) { onPermissionGrantResultSingleState(foregroundGroupState, false, true); } if (backgroundGroupState != null) { onPermissionGrantResultSingleState(backgroundGroupState, false, true); } break; } if (!showNextPermissionGroupGrantRequest()) { setResultAndFinish(); } } //省略部分代码 }

可以看到最终都会执行onPermissionGrantResultSingleState()

private void onPermissionGrantResultSingleState(GroupState groupState, boolean granted, boolean doNotAskAgain) { if (groupState != null && groupState.mGroup != null && groupState.mState == GroupState.STATE_UNKNOWN) { if (granted) { //用户允许授权 groupState.mGroup.grantRuntimePermissions(doNotAskAgain, groupState.affectedPermissions); groupState.mState = GroupState.STATE_ALLOWED; reportRequestResult(groupState.affectedPermissions, PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_GRANTED); } else { //用户拒绝授权 groupState.mGroup.revokeRuntimePermissions(doNotAskAgain, groupState.affectedPermissions); groupState.mState = GroupState.STATE_DENIED; reportRequestResult(groupState.affectedPermissions, doNotAskAgain ? PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED_WITH_PREJUDICE : PERMISSION_GRANT_REQUEST_RESULT_REPORTED__RESULT__USER_DENIED); } } }

看看允许授权的逻辑

public boolean grantRuntimePermissions(boolean fixedByTheUser, String[] filterPermissions) { boolean killApp = false; boolean wasAllGranted = true; //权限状态配置 // We toggle permissions only to apps that support runtime // permissions, otherwise we toggle the app op corresponding // to the permission if the permission is granted to the app. for (Permission permission : mPermissions.values()) { if (filterPermissions != null && !ArrayUtils.contains(filterPermissions, permission.getName())) { continue; } if (!permission.isGrantingAllowed(mIsEphemeralApp, mAppSupportsRuntimePermissions)) { // Skip unallowed permissions. continue; } boolean wasGranted = permission.isGrantedIncludingAppOp(); if (mAppSupportsRuntimePermissions) { // Do not touch permissions fixed by the system. if (permission.isSystemFixed()) { wasAllGranted = false; break; } // Ensure the permission app op enabled before the permission grant. if (permission.affectsAppOp() && !permission.isAppOpAllowed()) { permission.setAppOpAllowed(true); } // Grant the permission if needed. if (!permission.isGranted()) { permission.setGranted(true); } // Update the permission flags. if (!fixedByTheUser) { // Now the apps can ask for the permission as the user // no longer has it fixed in a denied state. if (permission.isUserFixed() || permission.isUserSet()) { permission.setUserFixed(false); permission.setUserSet(false); } } } else { // Legacy apps cannot have a not granted permission but just in case. if (!permission.isGranted()) { continue; } // If the permissions has no corresponding app op, then it is a // third-party one and we do not offer toggling of such permissions. if (permission.affectsAppOp()) { if (!permission.isAppOpAllowed()) { permission.setAppOpAllowed(true); // Legacy apps do not know that they have to retry access to a // resource due to changes in runtime permissions (app ops in this // case). Therefore, we restart them on app op change, so they // can pick up the change. killApp = true; } // Mark that the permission should not be be granted on upgrade // when the app begins supporting runtime permissions. if (permission.shouldRevokeOnUpgrade()) { permission.setRevokeOnUpgrade(false); } } // Granting a permission explicitly means the user already // reviewed it so clear the review flag on every grant. if (permission.isReviewRequired()) { permission.unsetReviewRequired(); } } // If we newly grant background access to the fine location, double-guess the user some // time later if this was really the right choice. if (!wasGranted && permission.isGrantedIncludingAppOp()) { if (permission.getName().equals(ACCESS_FINE_LOCATION)) { Permission bgPerm = permission.getBackgroundPermission(); if (bgPerm != null) { if (bgPerm.isGrantedIncludingAppOp()) { mTriggerLocationAccessCheckOnPersist = true; } } } else if (permission.getName().equals(ACCESS_BACKGROUND_LOCATION)) { ArrayList fgPerms = permission.getForegroundPermissions(); if (fgPerms != null) { int numFgPerms = fgPerms.size(); for (int fgPermNum = 0; fgPermNum < numFgPerms; fgPermNum++) { Permission fgPerm = fgPerms.get(fgPermNum); if (fgPerm.getName().equals(ACCESS_FINE_LOCATION)) { if (fgPerm.isGrantedIncludingAppOp()) { mTriggerLocationAccessCheckOnPersist = true; } break; } } } } } } if (!mDelayChanges) { //这里很重要,将授权信息持久化保存到本地 persistChanges(false); if (killApp) { killApp(KILL_REASON_APP_OP_CHANGE); } } return wasAllGranted; }

授权过程就是本地数据配置的过程,最后有一个逻辑很关键,就是将授权信息进行持久化保存,因为当我们关机重启后,需要恢复各个app的授权信息,看看保存到哪儿了

void persistChanges(boolean mayKillBecauseOfAppOpsChange) { int uid = mPackageInfo.applicationInfo.uid; int numPermissions = mPermissions.size(); boolean shouldKillApp = false; for (int i = 0; i < numPermissions; i++) { Permission permission = mPermissions.valueAt(i); if (!permission.isSystemFixed()) { if (permission.isGranted()) { mPackageManager.grantRuntimePermission(mPackageInfo.packageName, permission.getName(), mUserHandle); } else { boolean isCurrentlyGranted = mContext.checkPermission(permission.getName(), -1, uid) == PERMISSION_GRANTED; if (isCurrentlyGranted) { mPackageManager.revokeRuntimePermission(mPackageInfo.packageName, permission.getName(), mUserHandle); } } } int flags = (permission.isUserSet() ? PackageManager.FLAG_PERMISSION_USER_SET : 0) | (permission.isUserFixed() ? PackageManager.FLAG_PERMISSION_USER_FIXED : 0) | (permission.shouldRevokeOnUpgrade() ? PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE : 0) | (permission.isPolicyFixed() ? PackageManager.FLAG_PERMISSION_POLICY_FIXED : 0) | (permission.isReviewRequired() ? PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED : 0); //更新权限标识位,这里是去更新PMS里面当前app的权限配置 mPackageManager.updatePermissionFlags(permission.getName(), mPackageInfo.packageName, PackageManager.FLAG_PERMISSION_USER_SET | PackageManager.FLAG_PERMISSION_USER_FIXED | PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE | PackageManager.FLAG_PERMISSION_POLICY_FIXED | PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, flags, mUserHandle); if (permission.affectsAppOp()) { if (!permission.isSystemFixed()) { // Enabling/Disabling an app op may put the app in a situation in which it has // a handle to state it shouldn't have, so we have to kill the app. This matches // the revoke runtime permission behavior. if (permission.isAppOpAllowed()) { shouldKillApp |= allowAppOp(permission, uid); } else { shouldKillApp |= disallowAppOp(permission, uid); } } } } if (mayKillBecauseOfAppOpsChange && shouldKillApp) { killApp(KILL_REASON_APP_OP_CHANGE); } if (mTriggerLocationAccessCheckOnPersist) { new LocationAccessCheck(mContext, null).checkLocationAccessSoon(); mTriggerLocationAccessCheckOnPersist = false; } }

这里通过AIDL,将当前授权信息发送给PMS,使得PMS中保存的当前app的授权信息得以更新

@Override public void updatePermissionFlags(String permissionName, String packageName, int flagMask, int flagValues, UserHandle user) { try { //跨进程调用,执行PackageManagerService的updatePermissionFlags() mPM.updatePermissionFlags(permissionName, packageName, flagMask, flagValues, mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q, user.getIdentifier()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }

看看PackageManagerService的处理

@Override public void updatePermissionFlags(String permName, String packageName, int flagMask, int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) { int callingUid = getCallingUid(); boolean overridePolicy = false; if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) { long callingIdentity = Binder.clearCallingIdentity(); try { if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0) { if (checkAdjustPolicyFlagPermission) { mContext.enforceCallingOrSelfPermission( Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, "Need " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " to change policy flags"); } else if (!hasTargetSdkInUidLowerThan(callingUid, Build.VERSION_CODES.Q)) { throw new IllegalArgumentException( Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " needs " + " to be checked for packages targeting " + Build.VERSION_CODES.Q + " or later when changing policy " + "flags"); } overridePolicy = true; } } finally { Binder.restoreCallingIdentity(callingIdentity); } } //通过PermissionManagerService操作 mPermissionManager.updatePermissionFlags( permName, packageName, flagMask, flagValues, callingUid, userId, overridePolicy, mPermissionCallback); }

最终更新的是PermissionManagerService当中的数据

private void updatePermissionFlags(String permName, String packageName, int flagMask, int flagValues, int callingUid, int userId, boolean overridePolicy, PermissionCallback callback) { //省略部分代码 //先获取PackageParser.Package final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName); //省略部分代码 //更新Package的mExtras final PackageSetting ps = (PackageSetting) pkg.mExtras; final PermissionsState permissionsState = ps.getPermissionsState(); final boolean hadState = permissionsState.getRuntimePermissionState(permName, userId) != null; final boolean permissionUpdated = permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues); if (permissionUpdated && bp.isRuntime()) { notifyRuntimePermissionStateChanged(packageName, userId); } if (permissionUpdated && callback != null) { // Install and runtime permissions are stored in different places, // so figure out what permission changed and persist the change. if (permissionsState.getInstallPermissionState(permName) != null) { //通知安装权限更新,就是不需要动态授权的权限 callback.onInstallPermissionUpdated(); } else if (permissionsState.getRuntimePermissionState(permName, userId) != null || hadState) { //通知动态权限状态更新 callback.onPermissionUpdated(new int[] { userId }, false); } } }

可以看到,最终更新的是PackageParser.Package的mExtras字段,上面我们分析知道,在检查权限时,也是读取的PackageParser.Package的mExtras字段,这里就跟前面的逻辑相呼应了,更新完之后,通过callback进行回调,执行持久化存储

@Override public void onPermissionUpdated(int[] updatedUserIds, boolean sync) { synchronized (mPackages) { for (int userId : updatedUserIds) { mSettings.writeRuntimePermissionsForUserLPr(userId, sync); } } } public void writeRuntimePermissionsForUserLPr(int userId, boolean sync) { if (sync) { mRuntimePermissionsPersistence.writePermissionsForUserSyncLPr(userId); } else { mRuntimePermissionsPersistence.writePermissionsForUserAsyncLPr(userId); } } private void writePermissionsSync(int userId) { //定义持久化保存路径 AtomicFile destination = new AtomicFile(getUserRuntimePermissionsFile(userId), "package-perms-" + userId); //省略部分代码 FileOutputStream out = null; try { //省略部分代码 //保存到本地 destination.finishWrite(out); if (Build.FINGERPRINT.equals(fingerprint)) { mDefaultPermissionsGranted.put(userId, true); } // Any error while writing is fatal. } catch (Throwable t) { Slog.wtf(PackageManagerService.TAG, "Failed to write settings, restoring backup", t); destination.failWrite(out); } finally { IoUtils.closeQuietly(out); } } //文件名 private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml"; //获取路径 private File getUserRuntimePermissionsFile(int userId) { // TODO: Implement a cleaner solution when adding tests. // This instead of Environment.getUserSystemDirectory(userId) to support testing. File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId)); File file = new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME); Log.d("jasonwan", "getUserRuntimePermissionsFile: file="+file.getAbsolutePath()); return file; }

通过log打印得知,权限文件路径位于/data/system/users/0/runtime-permissions.xml,我们从设备中导出此文件打开看看长啥样

可以看到此文件保存就是各个app的动态权限授权情况,安装权限不在此文件中,我们的测试demo包名为com.jason.nodetest,可以看到我们只允许读存储卡权限后,读写权限均为已授权。

同样,当系统重启后,PackageManagerService会初始化并启动,初始化时会从UserServiceManager中获取读取的权限数据

public class PackageManagerService extends IPackageManager.Stub implements PackageSender { //省略部分代码 public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { //省略部分代码 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "read user settings"); //UserManager创建用户时会去读取用户配置文件,其中就包括runtime-permissions.xml文件 mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false)); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); //省略部分代码 } //省略部分代码 } boolean readLPw(@NonNull List users) { //省略部分代码 for (UserInfo user : users) { //读取所有用户配置信息 mRuntimePermissionsPersistence.readStateForUserSyncLPr(user.id); } //省略部分代码 } @GuardedBy("Settings.this.mLock") public void readStateForUserSyncLPr(int userId) { //获取runtime-permissions.xml文件 File permissionsFile = getUserRuntimePermissionsFile(userId); if (!permissionsFile.exists()) { return; } FileInputStream in; try { in = new AtomicFile(permissionsFile).openRead(); } catch (FileNotFoundException fnfe) { Slog.i(PackageManagerService.TAG, "No permissions state"); return; } try { XmlPullParser parser = Xml.newPullParser(); parser.setInput(in, null); //解析runtime-permissions.xml文件 parseRuntimePermissionsLPr(parser, userId); } catch (XmlPullParserException | IOException e) { throw new IllegalStateException("Failed parsing permissions file: " + permissionsFile , e); } finally { IoUtils.closeQuietly(in); } } @GuardedBy("Settings.this.mLock") private void parseRuntimePermissionsLPr(XmlPullParser parser, int userId) throws IOException, XmlPullParserException { final int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } switch (parser.getName()) { case TAG_RUNTIME_PERMISSIONS: { // If the permisions settings file exists but the version is not set this is // an upgrade from P->Q. Hence mark it with the special UPGRADE_VERSION int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION, UPGRADE_VERSION); mVersions.put(userId, version); String fingerprint = parser.getAttributeValue(null, ATTR_FINGERPRINT); mFingerprints.put(userId, fingerprint); final boolean defaultsGranted = Build.FINGERPRINT.equals(fingerprint); mDefaultPermissionsGranted.put(userId, defaultsGranted); } break; case TAG_PACKAGE: { String name = parser.getAttributeValue(null, ATTR_NAME); PackageSetting ps = mPackages.get(name); if (ps == null) { Slog.w(PackageManagerService.TAG, "Unknown package:" + name); XmlUtils.skipCurrentTag(parser); continue; } parsePermissionsLPr(parser, ps.getPermissionsState(), userId); } break; case TAG_SHARED_USER: { //读取shared-user标签,拿到包名 String name = parser.getAttributeValue(null, ATTR_NAME); SharedUserSetting sus = mSharedUsers.get(name); if (sus == null) { Slog.w(PackageManagerService.TAG, "Unknown shared user:" + name); XmlUtils.skipCurrentTag(parser); continue; } //解析shared-user下的所有item权限 parsePermissionsLPr(parser, sus.getPermissionsState(), userId); } break; } } } private void parsePermissionsLPr(XmlPullParser parser, PermissionsState permissionsState, int userId) throws IOException, XmlPullParserException { final int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } switch (parser.getName()) { case TAG_ITEM: { //读取权限名称 String name = parser.getAttributeValue(null, ATTR_NAME); BasePermission bp = mPermissions.getPermission(name); if (bp == null) { Slog.w(PackageManagerService.TAG, "Unknown permission:" + name); XmlUtils.skipCurrentTag(parser); continue; } //读取权限授权状态 String grantedStr = parser.getAttributeValue(null, ATTR_GRANTED); final boolean granted = grantedStr == null || Boolean.parseBoolean(grantedStr); //读取权限的flag String flagsStr = parser.getAttributeValue(null, ATTR_FLAGS); final int flags = (flagsStr != null) ? Integer.parseInt(flagsStr, 16) : 0; //给权限赋值 if (granted) { permissionsState.grantRuntimePermission(bp, userId); permissionsState.updatePermissionFlags(bp, userId, PackageManager.MASK_PERMISSION_FLAGS_ALL, flags); } else { permissionsState.updatePermissionFlags(bp, userId, PackageManager.MASK_PERMISSION_FLAGS_ALL, flags); } } break; } }

可以看到,从runtime-permissions.xml文件中读取的授权信息最终赋值给了PermissionsState,而我们在检查权限时也是从PermissionState中获取的权限授权状态,这里跟前面形成了闭环。

总结

以上就是Android 10动态授权的整个流程,简单总结下就是

1、Android启动,PackageManagerService启动,扫描APK获取所有权限

2、读取runtime-permissions.xml文件,获取动态权限授权情况,并将他赋值给PermissionState

3、用户检查权限,从PermissionState中获取目标权限的授权状态,并返给app

4、用户申请权限,根据用户的选择,设置PermissionState中对应权限的状态,并持久化存储到runtime-permissions.xml文件中



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有